package cn.cangfei.massage.service.impl;

import cn.cangfei.massage.constant.RedisConstants;
import cn.cangfei.massage.dto.*;
import cn.cangfei.massage.dto.param.VisitPlanParam;
import cn.cangfei.massage.dto.param.VisitPlanUpdateParam;
import cn.cangfei.massage.dto.update.AppointmentForDoctor;
import cn.cangfei.massage.dto.update.AppointmentItem;
import cn.cangfei.massage.dto.update.VisitAppointmentDto;
import cn.cangfei.massage.entity.*;
import cn.cangfei.massage.exception.YyghException;
import cn.cangfei.massage.mapper.VisitAppointmentMapper;
import cn.cangfei.massage.mapper.VisitPlanMapper;
import cn.cangfei.massage.service.*;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.date.DateUtil;
import com.alibaba.fastjson.JSON;
import com.github.pagehelper.PageHelper;
import lombok.extern.slf4j.Slf4j;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.springframework.beans.BeanUtils;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;

import javax.annotation.Resource;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Optional;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;
import java.util.*;

/**
 * @author Lemon  2313812755@qq.com
 * @date 2023/3/1
 */
@Slf4j
@Service
public class VisitPlanServiceImpl implements IVisitPlanService {

    /**
     * 每段时间内 最大就诊人数
     */
    private static final Integer MAX_OF_PATIENTS = 5;

    @Resource
    private VisitAppointmentMapper appointmentMapper;

    @Resource
    private StringRedisTemplate stringRedisTemplate;

    @Resource
    private RedissonClient redissonClient;

    @Resource
    private VisitPlanMapper planMapper;

    @Resource
    private IMassageDoctorService massageDoctorService;

    @Resource
    private IMassageClinicService massageClinicService;

    @Resource
    private IMassageInfoService massageInfoService;

    @Resource
    private IMassageOutpatientService massageOutpatientService;

    @Resource
    private IMassageSpecialService massageSpecialService;

    @Resource
    private IVisitAppointmentService appointmentService;


    @Resource
    private IUserBasicInfoService userBasicInfoService;

    /**
     * 创建出诊计划
     *
     * @param param 出诊计划参数
     * @return 是否成功
     */
    @Override
    public boolean insertAll(VisitPlanParam param) {
        // 先根据doctorId去查询
        Long doctorId = param.getDoctorId();
        VisitPlanExample visitPlanExample = new VisitPlanExample();
        visitPlanExample.createCriteria().andDoctorIdEqualTo(doctorId);
        long l = planMapper.countByExample(visitPlanExample);
        if (l > 0) {
            throw new YyghException(500, "该师傅已存在出诊计划");
        }

        VisitPlan plan = new VisitPlan();

        BeanUtils.copyProperties(param, plan);

        plan.setGmtCreate(new Date());
        plan.setGmtModified(new Date());

        // 这里出入的话没有问题的
        return planMapper.insertSelective(plan) > 0;
    }

    /**
     * 更新出诊计划
     *
     * @param id    记录编号
     * @param param 出诊计划参数
     * @return 是否成功
     */
    @Override
    public boolean update(Long id, VisitPlanUpdateParam param) {

        VisitPlan plan = new VisitPlan();

        BeanUtils.copyProperties(param, plan);

        plan.setId(id);
        plan.setGmtModified(new Date());

        // 删除redis
        String key = RedisConstants.PLAN_INFO_PREFIX + plan.getDoctorId();
        // 删除redis中的doctor_info的前缀全部删除
        Set<String> keys = stringRedisTemplate.keys(RedisConstants.DOCTOR_INFO_PREFIX + "*");
        if (keys != null && keys.size() > 0) {
            stringRedisTemplate.delete(keys);
        }


        stringRedisTemplate.delete(key);

        return planMapper.updateByPrimaryKeySelective(plan) > 0;
    }

    /**
     * 获取出诊计划
     *
     * @param id 计划编号
     * @return 出诊计划
     */
    @Override
    public Optional<VisitPlanDTO> getOptional(Long id) {
        return Optional.of(covert(planMapper.selectByPrimaryKey(id)));
    }

    /**
     * 删除出诊计划
     *
     * @param idList 计划编号
     * @return 是否成功
     */
    @Override
    public boolean deleteAll(List<Long> idList) {
        VisitPlanExample example = new VisitPlanExample();

        example.createCriteria()
                .andIdIn(idList);

        // 先查询出来，批量删除
        List<VisitPlan> visitPlans = planMapper.selectByExample(example);
        if (CollUtil.isEmpty(visitPlans)) {
            return false;
        }
        // 删除redis，使用批量删除
        visitPlans.forEach((item) -> {
            String key = RedisConstants.PLAN_INFO_PREFIX + item.getDoctorId();
            stringRedisTemplate.delete(key);
        });

        return planMapper.deleteByExample(example) > 0;
    }

    /**
     * 删除出诊计划
     *
     * @param id 计划编号
     * @return 是否成功
     */
    @Transactional
    @Override
    public boolean delete(Long id) {
        // 先查询出来
        VisitPlan visitPlan = planMapper.selectByPrimaryKey(id);
        if (visitPlan == null) {
            throw new YyghException(500, "该计划不存在");
        }
        // 删除redis
        String key = RedisConstants.PLAN_INFO_PREFIX + visitPlan.getDoctorId();
        stringRedisTemplate.delete(key);
        // 还要删除预约表里面的预约planId
        appointmentService.deleteWithPlanId(id);
        return planMapper.deleteByPrimaryKey(id) > 0;
    }

    /**
     * 判断是否，存在该计划
     *
     * @param id 计划编号
     * @return 是否存在
     */
    @Override
    public boolean count(Long id) {

        VisitPlanExample example = new VisitPlanExample();

        example.createCriteria()
                .andIdEqualTo(id);

        return planMapper.countByExample(example) > 0;
    }

    /**
     * 获取师傅出诊信息
     *
     * @param doctorId 师傅编号
     * @param start    开始日期
     * @param end      结束日期
     * @return 师傅出诊信息
     */
    @Override
    public VisitDoctorPlanDTO getDoctorPlan(Long doctorId, Date start, Date end) {

        VisitDoctorPlanDTO dto = new VisitDoctorPlanDTO();

        // 设置师傅信息
        if (massageDoctorService.getConvert(doctorId).isPresent()) {
            dto.setDoctorDTO(massageDoctorService.getConvert(doctorId).get());
        }

        // 设置师傅出诊信息列表
        dto.setPlanListDTOList(getVisitPlanDTO(doctorId, start, end));

        return dto;
    }

    /**
     * 获取师傅出诊信息
     *
     * @param massageId 推拿馆编号
     * @param doctorId   师傅编号
     * @param week       星期
     * @return 师傅出诊信息
     */
    @Override
    public List<VisitPlanResiduesDTO> getDoctorPlanByDate(Long massageId, Long doctorId, String week, String date) {
        List<VisitPlan> list = new ArrayList<>();
        // 先从redis里面获取
        String key = RedisConstants.PLAN_INFO_PREFIX + doctorId;
        String jsonStr = stringRedisTemplate.opsForValue().get(key);
        VisitPlan visitPlan = null;
        if (StringUtils.isEmpty(jsonStr)) {
            // 获取当天出诊计划
            VisitPlanExample example = new VisitPlanExample();

            example.createCriteria()
                    .andDoctorIdEqualTo(doctorId)
                    .andMassageIdEqualTo(massageId);

            // 注意绝对只有一个
            list = planMapper.selectByExample(example);
            // 放入到缓存里面去
            if (CollUtil.isEmpty(list)) {
                return null;
            }
            visitPlan = list.get(0);
            // 这个是出诊计划
            jsonStr = JSON.toJSONString(visitPlan);
            stringRedisTemplate.opsForValue().set(key, jsonStr);

        } else {
            visitPlan = JSON.parseObject(jsonStr, VisitPlan.class);
            list.add(visitPlan);

        }

        List<VisitPlan> collect = list.stream().filter((item) -> {
            String day = item.getDay();
            String[] split = day.split(",");
            // 也就是这天要上班的
            // 这个人所有的班的星期
            List<String> list1 = Arrays.asList(split);
            // week表示今天星期几
            return list1.contains(week);
        }).collect(Collectors.toList());


        // 每一个计划，我们根据doctorId来进行关联
        if (CollUtil.isEmpty(collect)) {
            return null;
        }

        return collect.stream()
                .map((item) -> {
                    // date表示查询的是哪一天的
                    return covertToResidues(date, item, massageId);
                })
                .collect(Collectors.toList());
    }

    /**
     * 查找出诊列表
     *
     * @param massageId   推拿馆编号
     * @param specialId    专科编号
     * @param outpatientId 门诊编号
     * @param doctorId     师傅编号
     * @param week         出诊星期
     * @param pageNum      第几页
     * @param pageSize     页大小
     * @return 出诊列表
     */
    @Override
    public List<VisitPlanDTO> list(Long massageId, Long specialId, Long outpatientId, Long doctorId, String week,
                                   Integer pageNum, Integer pageSize) {

        PageHelper.startPage(pageNum, pageSize);

        VisitPlanExample example = new VisitPlanExample();

        VisitPlanExample.Criteria criteria = example.createCriteria();

        if (massageId != null) {
            criteria.andMassageIdEqualTo(massageId);
        }

        if (doctorId != null) {
            criteria.andDoctorIdEqualTo(doctorId);
        }

        List<VisitPlan> visitPlans = planMapper.selectByExample(example);
        if (visitPlans == null) {
            return null;
        }
        List<VisitPlan> collect = visitPlans.stream().filter((item) -> {
            String day = item.getDay();
            String[] split = day.split(",");
            List<String> list = Arrays.asList(split);
            return list.contains(week);
        }).collect(Collectors.toList());


        return collect.stream()
                .map(this::covert)
                .collect(Collectors.toList());
    }


    /**
     * 获取某段时间出诊计划
     *
     * @param start 开始时间
     * @param end   结束时间
     * @return 出诊计划编号
     */
    @Override
    public List<Long> list(Date start, Date end) {
        VisitPlanExample example = new VisitPlanExample();

        example.createCriteria()
                .andDayGreaterThanOrEqualTo(start)
                .andDayLessThanOrEqualTo(end);

        return planMapper.selectByExample(example).stream()
                .map(VisitPlan::getId).collect(Collectors.toList());
    }

    /**
     * 定时扫描请假表来进行删除的
     */
    @Scheduled(cron = "0 0/5 * * * ?")
    @Transactional
    @Override
    public void deleteJia() {
        RLock lock = redissonClient.getLock("chidao");
        lock.lock(15, TimeUnit.SECONDS);
        try {
            log.info("开始执行定时扫描请假表来进行删除的");
            // 首先获取所有的表里面的数据
            List<VisitPlan> plans = planMapper.getAll();
            // 循环遍历 把里面请假表的日期给一个一个弄为集合，然后判断今天的日期是否小于，如果小于的话就要进行更新处理
            plans.forEach((plan) -> {
                String jia = plan.getJia();
                System.out.println("plan: " + plan);
                // 注意这里不能在取出空格了
                if (!StringUtils.isEmpty(jia)) {


                    String[] split = jia.split(",");
                    // 得到这个日期集合
                    List<String> list = Arrays.asList(split);

                    SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd");
                    Date dateToday = new Date();
                    // 今天
                    String format = formatter.format(dateToday);
                    // 加个年份上去
                    // System.out.println(format);
                    // 存储过期的
                    List<Integer> shoujiGuoqixiabiao = new ArrayList<>();
                    List<String> shoujiBuGuoqixiabiao = new ArrayList<>();
                    try {
                        // 今天的日期转换为月-日
                        Date date1 = formatter.parse(format);
                        // System.out.println("今天日期：" + date1);
                        // 将里面的转为日期
                        int size = list.size();
                        for (int i = 0; i < size; i++) {
                            String s = list.get(i);

                            // 与今天的作比较
                            // s1表示请假日期
                            if ((format.compareTo(s)) > 0) {
                                // 大于的话就将list里面的数据弹出
                                shoujiGuoqixiabiao.add(i);
                            } else {
                                shoujiBuGuoqixiabiao.add(s);
                            }

                        }

                        // 先将原来地修改为空
                        planMapper.updateJia(plan.getDoctorId(), "");
                        StringBuilder jiaString = new StringBuilder();

                        // 遍历shoujiBuGuoqixiabiao生成新的jiaString
                        for (int i = 0; i < shoujiBuGuoqixiabiao.size(); i++) {
                            if (i != shoujiBuGuoqixiabiao.size() - 1) {
                                jiaString.append(shoujiBuGuoqixiabiao.get(i)).append(",");
                            } else {
                                jiaString.append(shoujiBuGuoqixiabiao.get(i));
                            }
                        }
                        System.out.println("jiaString: " + jiaString);
                        System.out.println("doctorId: " + plan.getDoctorId());

                        // 将planId 和 需要修改的假期给弄回来
                        // 根据师傅来的
                        planMapper.updateJia(plan.getDoctorId(), jiaString.toString());
                    } catch (ParseException e) {
                        e.printStackTrace();
                    } finally {
                        // 因为开启了多线程
                        if (lock.isLocked() && lock.isHeldByCurrentThread()) {
                            // 解锁
                            lock.unlock();
                        }
                    }
                }


            });
        } finally {
            // 因为开启了多线程
            if (lock.isLocked() && lock.isHeldByCurrentThread()) {
                // 解锁
                lock.unlock();
            }
        }
    }

    @Override
    public void getJia(Jia jia) {
        // 根据师傅id来修改原来地请假为空
        Long doctorId = jia.getDoctorId();
        // 先根据id获取出来
        VisitPlan planByDoctorId = planMapper.getPlanByDoctorId(doctorId);
        if (planByDoctorId == null) {
            throw new YyghException(500, "该师傅没有出诊计划");
        }
        // 先将原来地修改为空
        planMapper.updateJia(doctorId, "");
        // 再将新地请假日期给添加进去
        String jia1 = jia.getJia();
        if (StringUtils.isEmpty(jia1.trim())) {
            return;
        }
        // 去新增在后面
        planMapper.updateJia(doctorId, jia1);

        // 删除redis
        String key = RedisConstants.PLAN_INFO_PREFIX + doctorId;
        stringRedisTemplate.delete(key);

        Set<String> keys = stringRedisTemplate.keys(RedisConstants.DOCTOR_INFO_PREFIX + "*");
        if (keys != null && keys.size() > 0) {
            stringRedisTemplate.delete(keys);
        }

    }

    /**
     * 请假接口
     *
     * @param jia
     *
     @Override public void getJia(Jia jia) {
     // 先删除原来的
     // 根据师傅id来删除
     Long doctorId = jia.getDoctorId();
     String jia1 = jia.getJia();
     // 必须让师傅有出诊计划
     VisitPlan planByDoctorId = planMapper.getPlanByDoctorId(doctorId);
     if (planByDoctorId == null) {
     throw new YyghException(500, "该师傅没有出诊计划");
     }

     if (StringUtils.isEmpty(jia1.trim())) {
     return;
     }
     // 去新增在后面
     // 但是要先判断一下
     // 先根据id获取出来
     VisitPlan plan = planMapper.getPlanByDoctorId(doctorId);

     // 判断为不为空
     if (StringUtils.isEmpty(plan.getJia())) {
     // 为空的话就直接新增
     planMapper.updateJia(doctorId, jia1);
     return;
     } else {
     // 不为空的话就要进行判断
     // 先判断是否已经存在
     String[] split1 = jia1.split(",");
     String[] split2 = plan.getJia().split(",");
     List<String> list1 = Arrays.asList(split1);
     List<String> list2 = Arrays.asList(split2);
     // 如果已经存在的话就不用添加了
     for (String s : list1) {
     if (list2.contains(s)) {
     throw new YyghException(500, "当天已请假不能重复添加");
     }
     }
     }

     // 在添加在后面
     StringBuilder jia2 = new StringBuilder(plan.getJia());
     String[] split = jia2.toString().split(",");
     List<String> list = Arrays.asList(split);

     // 这个是新增的
     String[] split1 = jia1.split(",");
     String[] list1 = split1;
     // 这个是数组库原本你的
     for (String s : list1) {
     if (!list.contains(s)) {
     // 才加入
     jia2.append(",").append(s);
     }
     }
     System.out.println("jia2:" + jia2);


     // 再进行修改
     planMapper.updateJia(doctorId, jia2.toString());
     }*/

    /**
     * 获取假期
     *
     * @param doctorId
     * @return
     */
    @Override
    public String getJia(Long doctorId) {
        // 从redis中
        String key = RedisConstants.PLAN_INFO_PREFIX + doctorId;
        String jsonStr = stringRedisTemplate.opsForValue().get(key);
        VisitPlan visitPlan = null;
        if (StringUtils.isEmpty(jsonStr)) {
            // 根据doctorId来获取
            visitPlan = planMapper.getVisitPlanByDoctorId(doctorId);
            // 转为json
            String str = JSON.toJSONString(visitPlan);
            stringRedisTemplate.opsForValue().set(key, str);
        } else {
            visitPlan = JSON.parseObject(jsonStr, VisitPlan.class);

        }
        String jia = visitPlan.getJia();
        // String jia = planMapper.getJia(doctorId);
        return jia;
    }

    /**
     * 修改上班每周的接口
     *
     * @param updateDay
     */
    @Override
    public void updateDay(UpdateDay updateDay) {
        Long doctorId = updateDay.getDoctorId();
        String day = updateDay.getDay();
        // 删除redis
        String key = RedisConstants.PLAN_INFO_PREFIX + doctorId;
        stringRedisTemplate.delete(key);

        Set<String> keys = stringRedisTemplate.keys(RedisConstants.DOCTOR_INFO_PREFIX + "*");
        if (keys != null && keys.size() > 0) {
            stringRedisTemplate.delete(keys);
        }
        planMapper.updateDay(doctorId, day);
    }

    /**
     * 获取时间段
     *
     * @param id
     * @return
     */
    @Override
    public String getDuan(Long id) {
        // 从redis中
        String key = RedisConstants.PLAN_INFO_PREFIX + id;
        String jsonStr = stringRedisTemplate.opsForValue().get(key);
        VisitPlan visitPlan = null;
        if (StringUtils.isEmpty(jsonStr)) {
            // 根据doctorId来获取
            visitPlan = planMapper.getVisitPlanByDoctorId(id);
            // 转为json
            String str = JSON.toJSONString(visitPlan);
            stringRedisTemplate.opsForValue().set(key, str);
        } else {
            visitPlan = JSON.parseObject(jsonStr, VisitPlan.class);

        }

        String shiJianDuan = visitPlan.getDuan();
        return shiJianDuan;
    }

    /**
     * 获取上班日期
     *
     * @param id
     * @return
     */
    @Override
    public String getDay(Long id) {
        // 从redis中
        String key = RedisConstants.PLAN_INFO_PREFIX + id;

        String jsonStr = stringRedisTemplate.opsForValue().get(key);
        VisitPlan visitPlan = null;
        if (StringUtils.isEmpty(jsonStr)) {
            // 根据doctorId来获取
            visitPlan = planMapper.getVisitPlanByDoctorId(id);
            // 转为json
            String str = JSON.toJSONString(visitPlan);
            stringRedisTemplate.opsForValue().set(key, str);
        } else {
            visitPlan = JSON.parseObject(jsonStr, VisitPlan.class);

        }
        String day = visitPlan.getDay();
        // String day = planMapper.getDay(id);
        return day;
    }

    /**
     * 根据师傅编号查询这个星期的预约人数情况
     *
     * @param doctorId
     * @return
     */
    @Override
    public List<AppointmentForDoctor> searchVisitPlanByDoctorAndDateAndWeek(Long doctorId) {
        List<AppointmentForDoctor> result = new ArrayList<>();
        // 看status就是0,1就可以 不能看2
        SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd");
        for (Date date : getWeekDay()) {
            AppointmentForDoctor appointmentForDoctor = new AppointmentForDoctor();
            List<AppointmentItem> appointmentItems = new ArrayList<>();
            // 获取到这个师傅的所有时间段
            VisitPlan planList = planMapper.getPlanByDoctorId(doctorId);
            String duan = planList.getDuan();
            // 将时间段分割
            String[] split = duan.split(",");

            // 每周一到周日的日期字符串格式
            String format = dateFormat.format(date);
            // 得到这天预约这个师傅并且没有取消的人数
            List<VisitAppointment> list = appointmentService.getYuYue(format, doctorId);
            if (list.size() == 0) {
                // 存放一个空进去
                appointmentForDoctor.setList(appointmentItems);
                appointmentForDoctor.setDay(format);
                result.add(appointmentForDoctor);
                continue;
            }
            // 如果不为空就要进行遍历
            list.forEach(item -> {
                // 订购时间
                Integer timePeriod = item.getTimePeriod();
                // 这个要注释因为会产生越界的影响
//                String shiJianDuan = split[timePeriod - 1];
                String shiJianDuan = item.getTime();
                // 姓名
                Long userId = item.getUserId();
                // 通过userId获取到姓名
                String userName = userBasicInfoService.getName(userId);
                Optional<UserBasicInfo> optional = userBasicInfoService.getOptional(userId);
                UserBasicInfo userBasicInfo = optional.get();
                String child = userBasicInfo.getChild();
                String phone = userBasicInfo.getPhone();

                AppointmentItem appointmentItem = new AppointmentItem();
                appointmentItem.setChildName(child);
                appointmentItem.setPhone(phone);
                appointmentItem.setUserName(userName);
                appointmentItem.setDuan(shiJianDuan);
                appointmentItems.add(appointmentItem);
            });

            // 根据时间段进行排序小的在前面
            List<AppointmentItem> collect = appointmentItems.stream().sorted((a1, a2) -> {
                String shiJianDuan1 = a1.getDuan();
                String shiJianDuan2 = a2.getDuan();
                String[] split1 = shiJianDuan1.split("-");
                String[] split2 = shiJianDuan2.split("-");
                // 时间小的在前面
                return split1[0].compareTo(split2[0]);
            }).collect(Collectors.toList());
            // 存放一个空进去
            appointmentForDoctor.setList(collect);
            appointmentForDoctor.setDay(format);


            result.add(appointmentForDoctor);
        }

        return result;
    }

    /**
     * 根据doctorId判断是否有这个师傅的出诊计划
     *
     * @param doctorId
     * @return
     */
    @Override
    public Integer getPlanByDoctorId(Long doctorId) {
        VisitPlan visitPlan = planMapper.getPlanByDoctorId(doctorId);
        return visitPlan == null ? 0 : 1;
    }


    /**
     * 获取本周的周一到周日的日期
     * 格式：yyyy-MM-dd这样的格式
     *
     * @return
     */
    public static Date[] getWeekDay() {
        Calendar calendar = Calendar.getInstance();
        while (calendar.get(Calendar.DAY_OF_WEEK) != Calendar.MONDAY) {
            calendar.add(Calendar.DAY_OF_WEEK, -1);
        }
        Date[] dates = new Date[7];  // new Date[7] 星期日
        for (int i = 0; i < 7; i++) {  // i < 7 星期日
            dates[i] = calendar.getTime();
            calendar.add(Calendar.DATE, 1);
        }
        return dates;
    }

    /**
     * 获取某天出诊计划信息
     *
     * @param doctorId 师傅编号
     * @param time     时间段：1 上午，2 下午
     * @param day      某天
     * @return 出诊计划列表
     */
    @Override
    public List<VisitPlan> getByTimeAndDate(Long doctorId, Integer time, Date day) {
        VisitPlanExample example = new VisitPlanExample();

        example.createCriteria()
                .andDoctorIdEqualTo(doctorId)
                .andTimeEqualTo(time)
                .andDayGreaterThanOrEqualTo(DateUtil.beginOfDay(day))
                .andDayLessThanOrEqualTo(DateUtil.endOfDay(day));

        return planMapper.selectByExample(example);
    }

    /**
     * 转换为出诊计划封装类
     * 增加诊室地址、师傅名称
     *
     * @param plan 出诊计划
     * @return 出诊计划封装类
     */
    private VisitPlanDTO covert(VisitPlan plan) {
        VisitPlanDTO dto = new VisitPlanDTO();

        BeanUtils.copyProperties(plan, dto);

        // 设置诊室地址
        dto.setClinicName(massageClinicService.getAddress(plan.getClinicId()));

        // 设置师傅名称
        dto.setDoctorName(massageDoctorService.getName(plan.getDoctorId()));

        // 设置门诊名称
        dto.setOutpatientName(massageOutpatientService.getName(plan.getOutpatientId()));

        // 设置专科名称
        dto.setSpecialName(massageSpecialService.getName(plan.getSpecialId()));

        // 设置推拿馆名称
        dto.setMassageName(massageInfoService.getName(plan.getMassageId()));

        return dto;
    }

    /**
     * 转换为出诊计划挂号封装类
     * 增加剩余挂号
     *
     * @param plan 出诊计划
     * @return 出诊计划封装类
     */
    private VisitPlanResiduesDTO covertToResidues(String day, VisitPlan plan, Long massageId) {

        VisitPlanResiduesDTO dto = new VisitPlanResiduesDTO();
        // 不需要
        // BeanUtils.copyProperties(plan, dto);
        dto.setPlanId(plan.getId());

        SimpleDateFormat dateFormat1 = new SimpleDateFormat("yyyy-MM-dd");
        List<Integer> residueList = new ArrayList<>();


        Date date1 = new Date();
        // 表示今天的年-月-日
        String format1 = dateFormat1.format(date1);

        // 获取到今天预约根据师傅id的信息
        Long doctorId1 = plan.getDoctorId();
        List<VisitAppointment> visitAppointmentList = appointmentService.getAppointmentListByToDayAndDoctorId(day, doctorId1, massageId);
        if (visitAppointmentList.isEmpty()) {
            dto.setAppointments(new ArrayList<>());
        } else {
            List<VisitAppointmentDto> collect = visitAppointmentList.stream()
                    /*.filter(item -> {
                        return item.getStatus() == 0;
                    })*/.map(item -> {
                        VisitAppointmentDto visitAppointmentDto = new VisitAppointmentDto();
                        BeanUtils.copyProperties(item, visitAppointmentDto);
                        Long userId = item.getUserId();
                        // 根据userId获取到孩子姓名和openId
                        // 先从缓存里面获取
                        String key = RedisConstants.USER_INFO_PREFIX + userId;
                        String jsonStr = stringRedisTemplate.opsForValue().get(key);
                        UserBasicInfo userBasicInfo = null;
                        if (StringUtils.isEmpty(jsonStr)) {
                            // 从数据库里面获取
                            Optional<UserBasicInfo> optional = userBasicInfoService.getOptional(userId);
                            userBasicInfo = optional.get();
                            // 放入到缓存里面去
                            jsonStr = JSON.toJSONString(userBasicInfo);
                            stringRedisTemplate.opsForValue().set(key, jsonStr);
                        } else {
                            userBasicInfo = JSON.parseObject(jsonStr, UserBasicInfo.class);
                        }

                        String child = userBasicInfo.getChild();
                        String openId = userBasicInfo.getOpenId();
                        visitAppointmentDto.setChildName(child);
                        visitAppointmentDto.setOpenId(openId);
                        return visitAppointmentDto;
                    }).sorted((item1, item2) -> {
                        return item1.getTimePeriod() - item2.getTimePeriod();
                    })
                    .collect(Collectors.toList());
            dto.setAppointments(collect);
        }

        Long doctorId = plan.getDoctorId();

        // 现在我还要获取时间段
        // 先从缓存里面获取
        String key = RedisConstants.PLAN_INFO_PREFIX + doctorId;
        String jsonStr = stringRedisTemplate.opsForValue().get(key);
        VisitPlan visitPlan = null;
        if (StringUtils.isEmpty(jsonStr)) {
            // 获取当天出诊计划
            VisitPlanExample example = new VisitPlanExample();

            example.createCriteria()
                    .andDoctorIdEqualTo(doctorId);

            // 注意绝对只有一个
            visitPlan = planMapper.selectByExample(example).get(0);
            // 放入到缓存里面去
            jsonStr = JSON.toJSONString(visitPlan);
            stringRedisTemplate.opsForValue().set(key, jsonStr);

        } else {
            visitPlan = JSON.parseObject(jsonStr, VisitPlan.class);
        }
        // 获取到时间段
        // String shijianduan = planMapper.getShiJianDuan(doctorId);
        String shijianduan = visitPlan.getDuan();
        String[] split = shijianduan.split(",");
        // 进行比较如果当前的已经过期了就要进行记录下标后面好重置
        int size = split.length;

        // 判断比传过来的data大如果大的话就直接设置为0;
        // 大于的话
        if (format1.compareTo(day) > 0) {
            for (int i = 0; i < size; i++) {
                // 过了当天全部返回-1
                residueList.add(-1);
            }

            dto.setResidues(residueList);
            return dto;
        }


        // 获取当前时间
        SimpleDateFormat dateFormat = new SimpleDateFormat("HH:mm");
        Date date = new Date();

        // TODO 获取当前师傅的就诊情况
        // 获取到当前的时间 就是09:00这样的样式
        String format = dateFormat.format(date);
        // 然后要和获取到的时间段进行比对
        // 将每一个时间段进行比较


        List<Integer> arr = new ArrayList<>();

        // 注意这里有问题，我们必须只有挂号今天的话才能判断日期
        if (format1.compareTo(day) == 0) {
            for (int i = 0; i < size; i++) {
                //
                String meigeshijianduan = split[i];

                // 取后面那一个
                String[] split1 = meigeshijianduan.split("-");
                String xuyaobijiaodeshijian = split1[1];
                // 当前时间只要大于等于了这个时间段最后那个时间就表示过期了
                if (format.compareTo(xuyaobijiaodeshijian) >= 0) {
                    // 这个要进行 + 1因为下面的timePeriod是从1开始的，最后全部-1进行统一处理就可以了
                    // 这里面就是过了时间段的
                    arr.add(i + 1);
                }


                // 就看当前的时间是不是大于等于这个时间段的截止时间如果是的话就记录进行后面好做统一的处理
            }
        }

        // 如果是往后的几天就不能进行时间判断，只判断这个时间段是否可以被……买了


        // 先根据plan的doctorId查询出appointment里面的这个人timePeriod
        // 然后将这个下标-1那个集合的位置变为0

        // day表示当时的获取时间


        // 这个是查询到挂号了的(没有取消的)
        // 这个就是需要进行检票的一个机制就可以了
        // 这个就是买过的
        // 这里还要判断状态必须是0,1因为2就表示取消了的
        // List<Integer> listTimePeriod = planMapper.getListTimePeriod(day, plan.getDoctorId());

        List<Integer> listTimePeriod = appointmentMapper.getListTimePeriod(day, plan.getDoctorId(), massageId);
        System.out.println("预约了的:" + listTimePeriod);
        // 判断一下是不是全部预约了
        /*if (listTimePeriod.size() == size) {
            for (int i = 0; i < size; i++) {
                // 现就就是这一天全部被人预约了的话就返回-2
                residueList.add(-2);
//                residueList.add(0);
            }
            dto.setResidues(residueList);
            return dto;
        }*/

        List<Integer> zuiZhong = new ArrayList<>();
        if (arr.size() > 0) {
            arr.forEach((item) -> {
                zuiZhong.add(item - 1);
            });
        }
        if (listTimePeriod.size() > 0) {
            listTimePeriod.forEach(item -> {
                zuiZhong.add(item - 1);
            });
        }

//        Integer timeperiod = appointmentService.getTimePeriodByDoctorId(doctorId);

        System.out.println("过了时间段的：" + arr);
        TimePeriodEnum timePeriod = (plan.getTime().equals(TimePeriodEnum.AM.getTime())) ? TimePeriodEnum.AM : TimePeriodEnum.PM;
//        System.out.println(zuizhong);
        // 这里先用集合进实现
        Integer[] zuizhongInteger = new Integer[size];
        for (int i = 0; i < size; i++) {

            // 有位置就是5
//            zuizhongInteger[i] = MAX_OF_PATIENTS - appointmentService.countByPlanId(plan.getId(), plan.getTime());
            zuizhongInteger[i] = 5;
            // 是否被预约
            if (listTimePeriod.size() > 0) {
                if (listTimePeriod.contains(i + 1)) {
                    zuizhongInteger[i] = -2;
                }
            }
            // 时间段
            if (arr != null) {
                if (arr.contains(i + 1)) {
                    zuizhongInteger[i] = -1;
                }
            }


        }

        for (int i = 0; i < size; i++) {
            residueList.add(zuizhongInteger[i]);
        }

        // 设置剩余号数
        dto.setResidues(residueList);

        return dto;
    }

    /**
     * 转换为出诊计划挂号封装类
     * 增加剩余挂号
     *
     * @param plan 出诊计划
     * @return 出诊计划封装类
     */
    private VisitPlanResiduesDTO covertToResidues(VisitPlan plan) {

        VisitPlanResiduesDTO dto = new VisitPlanResiduesDTO();

        // 先根据plan的doctorId查询出appointment里面的这个人timePerior
        // 然后将这个下标-1那个集合的位置变为0
        SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd");
        Date date = new Date();
        // 得到现在的时间格式
        String format = simpleDateFormat.format(date);
        Long doctorId = plan.getDoctorId();
        List<Integer> listTimePeriod = planMapper.getListTimePeriod(format, plan.getDoctorId());
        Integer timeperiod = appointmentService.getTimePeriodByDoctorId(doctorId);

        BeanUtils.copyProperties(plan, dto);

        List<Integer> residueList = new ArrayList<>();


        TimePeriodEnum timePeriod = (plan.getTime().equals(TimePeriodEnum.AM.getTime())) ? TimePeriodEnum.AM : TimePeriodEnum.PM;

        for (int i = timePeriod.getStart(); i <= timePeriod.getEnd(); i++) {

            if (timeperiod != null) {
                // TODO 让当前这个时间段直接为0
                // 设置剩余号数
                if (i == timeperiod - 1) {
                    residueList.add(0);
                } else {
                    residueList.add(MAX_OF_PATIENTS - appointmentService.countByPlanId(plan.getId(), plan.getTime()));
                }
            } else {
                // 设置剩余号数
                residueList.add(MAX_OF_PATIENTS - appointmentService.countByPlanId(plan.getId(), plan.getTime()));
            }
        }

        // 设置剩余号数
        dto.setResidues(residueList);

        return dto;
    }

    /**
     * 获取师傅，某段时间，以后出诊信息列表
     *
     * @param doctorId 师傅编号
     * @param start    获取该时间之后
     * @return 出诊列表
     */
    private List<VisitPlanListDTO> getVisitPlanDTO(Long doctorId, Date start, Date end) {

        // 查找师傅出诊信息列表
        List<VisitPlanListDTO> planDTOList = new ArrayList<>();

        VisitPlanExample example = new VisitPlanExample();

        example.createCriteria()
                .andDoctorIdEqualTo(doctorId)
                .andDayBetween(DateUtil.beginOfDay(start), DateUtil.endOfDay(end));

        planMapper.selectByExample(example).stream()
                // 按照不同推拿馆，进行分组
                .collect(Collectors.groupingBy(VisitPlan::getMassageId, Collectors.toList()))

                // 按照不同推拿馆，进行遍历
                .forEach((massageId, list) -> {

                    // 转换为师傅出诊列表
                    VisitPlanListDTO dto = new VisitPlanListDTO();

                    // 设置推拿馆信息
                    if (massageInfoService.getOptional(massageId).isPresent()) {
                        dto.setInfo(massageInfoService.getOptional(massageId).get());
                    }

                    // 设置师傅出诊列表
                    if (CollUtil.isNotEmpty(list)) {
                        dto.setPlanResiduesDTOList(list.stream()
                                .map(this::covertToResidues)
                                .collect(Collectors.toList()));
                    }

                    // 设置对应推拿馆中，师傅出诊计划信息
                    planDTOList.add(dto);

                });

        return planDTOList;
    }

}
